package futbol.tacticas.concursantes.TacticaFCLiga;

import java.awt.*;
import futbol.tacticas.*;
import futbol.tacticas.concursantes.Tactica;

import java.util.*;
import futbol.General;
import futbol.Partido;

/**
 *
 * @author Celso
 */
public class TacticaFCLiga implements Tactica 
{
    private double _xAnterior = Double.MIN_VALUE;
    private double _yAnterior = Double.MIN_VALUE;
    private double _m = Double.MIN_VALUE;
    private double _b = Double.MIN_VALUE;
    private double _yFutura = Double.MIN_VALUE;
    private ArrayList<Integer> _jugConComandos = new ArrayList<Integer>();
    
    private int _jugadores[][] =
    {
        {-160, 0, 6},
        {-135, 20, 7},
        {-135, -20, 7},
        {-95, 80, 7},
        {-95, -80, 6},
        {-53, 0, 6},
        {40, -75, 6},
        {40, 75, 6},
        {85, 30, 7},
        {85, -30, 7},
        {105, 0, 7}
    };
    
    public Color getColor1() 
    {
        return Color.RED;
    }

    public Color getColor2() 
    {
        return Color.BLACK;
    }

    public Color getColorNumero() 
    {
        return Color.WHITE;
    }

    public String getNombre() 
    {
        return "F.C. Liga";
    }

    public int getXInicial(int n) 
    {
        return _jugadores[n][0];
    }

    public int getYInicial(int n) 
    {
        return _jugadores[n][1];
    }

    public int getFuerza(int n) 
    {
        return _jugadores[n][2];
    }
    
    public Vector<Comando> getComandos(SituacionJugadores sj) 
    {
        _jugConComandos = new ArrayList<Integer>();
        
        Vector<Comando> comandosJugadores =new Vector();
        Point[] misJugadores = sj.getMisJugadores();
        
        //Posicionamiento
        for (int n=0;n<11;n++)
            comandosJugadores.add(new ComandoIrA(n,_jugadores[n][0],_jugadores[n][1]));
        
        //obtener la posicion de la bola
        Point posBola = sj.getBola();
        Point jugadores[]=sj.getMisJugadores();
        Point contrarios[]=sj.getContrario();
       
        double posYBola = posBola.getY();
        double posXBola = posBola.getX();
        
        if(_xAnterior != Double.MIN_VALUE)
        {
            _m = (posYBola - _yAnterior) / (posXBola - _xAnterior);
            _b = posYBola - _m * posXBola;
            
            _yFutura = _m * - 160 + _b;
        }
        
        int nJug;
        
        if(_xAnterior != Double.MIN_VALUE)
        { 
            double distX = posXBola - _xAnterior;
            double distY = posYBola - _yAnterior;
            
            //Movimiento mas cercano a la bola
            nJug = sj.getMiJugadorMasCerca(posXBola +  distX, posYBola + distY);

            //javax.swing.JOptionPane.showMessageDialog(null,  "X:" + Double.toString(posXBola +  distX) + " Y:" + Double.toString(posYBola +  distY));
            
            if(nJug == 0)
            {
                if(posYBola > 0)
                    comandosJugadores.add(new ComandoIrA(1, posXBola +  distX, posYBola + distY));
                else
                    comandosJugadores.add(new ComandoIrA(2, posXBola + distX, posYBola + distY));
            }
            else
            {
                comandosJugadores.add(new ComandoIrA(nJug, posBola.getX() + distX, posBola.getY() + distY));
            }
        }
        else
        {
            //Movimiento mas cercano a la bola
            nJug = sj.getMasCercanoDeBola();

            if(nJug == 0)
            {
                if(posYBola > 0)
                    comandosJugadores.add(new ComandoIrA(1, posXBola, posYBola));
                else
                    comandosJugadores.add(new ComandoIrA(2, posXBola, posYBola));
            }
            else
            {
                comandosJugadores.add(new ComandoIrA(nJug, posBola.getX(), posBola.getY()));
            }
        }
        
        //Mov de portero
        if(_yFutura == Double.MIN_VALUE && !(_yFutura >= (double) 35 && _yFutura <= (double) -35))
        {
            if(posYBola > 0 && posYBola < 35)
                comandosJugadores.add(new ComandoIrA(0, _jugadores[0][0], posYBola));
            else if (posYBola < 0 && posYBola > -35)
                comandosJugadores.add(new ComandoIrA(0, _jugadores[0][0], posYBola));
            else if (posYBola > 30)
                comandosJugadores.add(new ComandoIrA(0, _jugadores[0][0], 16));
            else if (posYBola <  -30)
                comandosJugadores.add(new ComandoIrA(0, _jugadores[0][0], -16));
        }
        else if (_yFutura <= (double) 35 && _yFutura >= (double) -35)
        {
            //javax.swing.JOptionPane.showMessageDialog(null, "X:" + Double.toString(-160) + " Y:" + Double.toString(_yFutura) + "X:" + Double.toString(posXBola) + " Y:" + Double.toString(posYBola));
            comandosJugadores.add(new ComandoIrA(0, -160, _yFutura));
        }
        
        //Golpear bola por el portero
        MovShuteoPortero(sj, comandosJugadores);
        
        //Mejorar defensa
        if (!sj.estoyMasCercaDeBola() || posXBola < 0)
        {
            for (int n=3;n<5;n++){
                int nJC=sj.getContrarioMasCerca(getXInicial(n), getYInicial(n));
                comandosJugadores.add(new ComandoIrA(n, contrarios[nJC].getX()+10, contrarios[nJC].getY()));
            }
        }
        
        //	PONGO LOS DEFENSAS A CUBRIR A LOS DELANTEROS
        for(int n=1;n<11;n++){
            if(nJug != n){
                if(sj.getContrario()[n].getX() <= 80){
                    int defMasCercano = sj.getMiJugadorMasCerca(sj.getContrario()[n].getX(),sj.getContrario()[n].getY());
                    if (defMasCercano <= 3 && defMasCercano != 0){
                        //jugadoresColocados.add(new Integer(defMasCercano));
                        if(posXBola < sj.getContrario()[n].getX()+20){
                        	if(posYBola > 0){
                        		if(posYBola > sj.getContrario()[n].getY()){
                        			comandosJugadores.add(new ComandoIrA(defMasCercano, sj.getContrario()[n].getX() - 8,sj.getContrario()[n].getY()+3));
                        		}else{
                        			comandosJugadores.add(new ComandoIrA(defMasCercano, sj.getContrario()[n].getX() - 8,sj.getContrario()[n].getY()-3));
                        		}
                        	}else{
                        		if(posYBola < sj.getContrario()[n].getY()){
                        			comandosJugadores.add(new ComandoIrA(defMasCercano, sj.getContrario()[n].getX() - 8,sj.getContrario()[n].getY()-3));
                        		}else{
                        			comandosJugadores.add(new ComandoIrA(defMasCercano, sj.getContrario()[n].getX() - 8,sj.getContrario()[n].getY()+3));
                        		}
                        	}
                        }else{
                            if(posXBola > 0){
                        		if(posYBola > sj.getContrario()[n].getY()){
                        			comandosJugadores.add(new ComandoIrA(defMasCercano, sj.getContrario()[n].getX() + 8,sj.getContrario()[n].getY()+3));
                        		}else{
                        			comandosJugadores.add(new ComandoIrA(defMasCercano, sj.getContrario()[n].getX() + 8,sj.getContrario()[n].getY()-3));
                        		}
                        	}else{
                        		if(posYBola < sj.getContrario()[n].getY()){
                        			comandosJugadores.add(new ComandoIrA(defMasCercano, sj.getContrario()[n].getX() + 8,sj.getContrario()[n].getY()-3));
                        		}else{
                        			comandosJugadores.add(new ComandoIrA(defMasCercano, sj.getContrario()[n].getX() + 8,sj.getContrario()[n].getY()+3));
                        		}
                        	}
                        }
                    }
                }
            }
        }
        
        /* //Mov defensa
        if (!sj.estoyMasCercaDeBola() || posBola.getX() < 0)
        {
            javax.swing.JOptionPane.showMessageDialog(null, _yFutura);
            for (int n=3;n<5;n++){
                int nJC=sj.getContrarioMasCerca(getXInicial(n), getYInicial(n));
                comandosJugadores.add(new ComandoIrA(n, contrarios[nJC].getX()+10, contrarios[nJC].getY()));
            }
        }*/
       
        _yFutura = _m * _jugadores[1][0] + _b;
        
        if(_yFutura > 0 && _yFutura < 30)
        {
           comandosJugadores.add(new ComandoIrA(1, _jugadores[1][0], _yFutura)); 
        }
        else if(posYBola > 0)
        {
             if(posYBola > 35)
             {
                comandosJugadores.add(new ComandoIrA(1, _jugadores[1][0], 35));
             }
             else
             {
                comandosJugadores.add(new ComandoIrA(1, _jugadores[1][0], posYBola));
             }
             comandosJugadores.add(new ComandoIrA(2, _jugadores[2][0], -5));
        }
        
        _yFutura = _m * _jugadores[2][0] + _b;
        
        if(_yFutura < 0 && _yFutura > -35)
        {
           comandosJugadores.add(new ComandoIrA(1, _jugadores[1][0], _yFutura)); 
        }
        else if(posYBola < 0)
        {
             if(posYBola < -35)
             {
                comandosJugadores.add(new ComandoIrA(2, _jugadores[2][0], -35));
             }
             else
             {
                comandosJugadores.add(new ComandoIrA(2, _jugadores[2][0], posYBola));
             }
             comandosJugadores.add(new ComandoIrA(1, _jugadores[1][0], 5));
        }
        
        int nJug2 = 0;
        
        //tratar de interceptar el balon
        if(_xAnterior != Double.MIN_VALUE)
        {
            for(int j = 5; j < 11; j++ )
            {
                Point jugador = misJugadores[j];

                double y = _m * jugador.x + _b; 

                if(distancia(jugador.x,y,jugador.x, jugador.y) <= 45)
                    comandosJugadores.add(new ComandoIrA(j, jugador.x, y));
            }
        }
        
         //Movimiento mas cercano a la bola
        if(_xAnterior != Double.MIN_VALUE)
        { 
            double distX = posXBola - _xAnterior;
            double distY = posYBola - _yAnterior;
            
            //Movimiento mas cercano a la bola
            nJug = sj.getMiJugadorMasCerca(posXBola + distX, posYBola + distY);

            if(nJug == 0)
            {
                if(posYBola > 0)
                    comandosJugadores.add(new ComandoIrA(1, posXBola +  distX, posYBola + distY));
                else
                    comandosJugadores.add(new ComandoIrA(2, posXBola + distX, posYBola + distY));
            }
            else
            {
                comandosJugadores.add(new ComandoIrA(nJug, posBola.getX() + distX, posBola.getY() + distY));
            }
        }
        else
        {
            //Movimiento mas cercano a la bola
            nJug = sj.getMasCercanoDeBola();

            if(nJug == 0)
            {
                if(posYBola > 0)
                    comandosJugadores.add(new ComandoIrA(1, posXBola, posYBola));
                else
                    comandosJugadores.add(new ComandoIrA(2, posXBola, posYBola));
            }
            else
            {
                comandosJugadores.add(new ComandoIrA(nJug, posBola.getX(), posBola.getY()));
            }
        }
        
        //comandosJugadores.add(new ComandoGolpearBola(0, -200, 110));
        hacerPase(sj, comandosJugadores);
        tirar(sj, comandosJugadores);
        /*comandosJugadores.add(new ComandoGolpearBola(1, 120, 110) );
        comandosJugadores.add(new ComandoGolpearBola(2, -120, 100) );
        
        comandosJugadores.add(new ComandoGolpearBola(nJug, 160, 10) );
        comandosJugadores.add(new ComandoGolpearBola(nJug2, 160, 10) );*/
        
        //bajar o subir los jugadores dependiendo de la posicion del balon
        for(int x = 5; x < 11; x++ )
        {
            if(x != nJug && x != nJug2)
            {
                if(posXBola > 0)
                    comandosJugadores.add(new ComandoIrA(x, _jugadores[x][0] + 25, _jugadores[x][1]));
                else
                    comandosJugadores.add(new ComandoIrA(x, _jugadores[x][0] - 20, _jugadores[x][1]));
            }
        }
        
        _yAnterior = posYBola;
        _xAnterior = posXBola;
        
        return comandosJugadores;
    }
    
    private void MovShuteoPortero(SituacionJugadores sj, Vector<Comando> comandosJugadores)
    {
        Point[] misJugadores = sj.getMisJugadores();
        
        //portero 
        Point portero = misJugadores[0];
        
        //obtener el contrario mas cercano al portero
        int contMasCercano = sj.getContrarioMasCerca(0);
        
        //si el portero no esta marcado y el jugador mas proximo esta libre
        if(!EstaCercaContario(sj, contMasCercano, portero.x, portero.y))
        {
            //sig jugador mas proximo 
            int sigJugador = sj.getSiguienteJugador(0);
            
            if(!EstaCercaContario(sj, sj.getContrarioMasCerca(sigJugador), misJugadores[sigJugador].x, misJugadores[sigJugador].y))
            {
                comandosJugadores.add(new ComandoGolpearBola(0, misJugadores[sigJugador].x, misJugadores[sigJugador].y));
            }
            else
                DespejePortero(sj, comandosJugadores);
        }
        else
            DespejePortero(sj, comandosJugadores);
    }
    
    private void hacerPase(SituacionJugadores sj, Vector<Comando> comandosJugadores)
    {
        Point[] misJugadores = sj.getMisJugadores();
        Point[] contarios = sj.getContrario();
        int mejorJugadorAPasar = 10;
        
        for(int j = 1; j < 6; j++)
        {
            double mejorNota = 0;
            
            int j2 = 1;
            
            if(j > 7)
            {
                comandosJugadores.add(new ComandoTiroAPuerta(j,0));
            }
            else
            {
                for (j2 = 1; j2 < 11; j2++)
                {

                    if(misJugadores[j2].x >= -109 && (distancia(misJugadores[j].x, misJugadores[j].y, misJugadores[j2].x, misJugadores[j2].y) <= 60.0))
                    {

                        double nota = 0;

                        if((j != j2) && (misJugadores[j2].x != misJugadores[j].x))
                        {
                            if(misJugadores[j2].x > 0)
                                nota += 25;

                            double m = (misJugadores[j2].y - misJugadores[j].y) / (misJugadores[j2].x - misJugadores[j].x);
                            double b = misJugadores[j].y - m * misJugadores[j].x;

                            for (int x = misJugadores[j].x; x <= misJugadores[j2].x; x = x + 10)
                            {
                                double y = m * x + b;

                                int contrario = sj.getContrarioMasCerca(x, y);

                                if(contrario >= 0 && contrario <= 25)
                                    nota += distancia(x, y, contarios[contrario].x, contarios[contrario].y);
                            }
                        }
                        else
                            //tirar(sj, comandosJugadores);
                            //DisparoPuerta(sj, comandosJugadores, j);
                            comandosJugadores.add(new ComandoTiroAPuerta(j,0));

                        if(mejorNota < nota)
                        {
                            mejorNota = nota;
                            mejorJugadorAPasar = j2;
                        }

                        comandosJugadores.add(new ComandoGolpearBola(j, misJugadores[mejorJugadorAPasar].x, misJugadores[mejorJugadorAPasar].y));
                        //comandosJugadores.add(new ComandoPase(j, mejorJugadorAPasar));
                    }
                    else
                        //tirar(sj, comandosJugadores);
                        //DisparoPuerta(sj, comandosJugadores, j);
                        comandosJugadores.add(new ComandoTiroAPuerta(j,0));
                }
            }
        }
    }
    
    private void DisparoPuerta(SituacionJugadores sj, Vector<Comando> comandosJugadores, int jugador)
    {
        Point[] misJugadores = sj.getMisJugadores();
        Point[] contrarios = sj.getContrario();
        double mejorNota = -99999;
        double mejorY = -99999;
        
        for(int i = 0; i < 30; i++)
        {
            double nota = 0.0;
            Random rand = new Random();
            double cordTiroY = rand.nextDouble() * 50.0;

            if(cordTiroY > 25)
            {
                cordTiroY -= 25;
                cordTiroY *= -1;
            }
            
            double m = (cordTiroY - misJugadores[jugador].y) / (160 - misJugadores[jugador].x);
            double b = misJugadores[jugador].y - m * misJugadores[jugador].x;
            
            for(int x = misJugadores[jugador].x; x < 160; x += 60)
            {
                double y = m * x + b;
                int contrarioMasCercano = sj.getContrarioMasCerca(x, y);
                
                nota += distancia(x, y, contrarios[contrarioMasCercano].x, contrarios[contrarioMasCercano].y); 
            }
            
            if(mejorNota <= nota)
            {
                mejorNota = nota;
                mejorY = cordTiroY;
            }
            
            comandosJugadores.add(new ComandoGolpearBola(jugador, 160, mejorY));
        }
    }
    
    private void DespejePortero(SituacionJugadores sj, Vector<Comando> comandosJugadores)
    {
        Point[] misJugadores = sj.getMisJugadores();
        Point[] contarios = sj.getContrario();
        
        //portero 
        Point portero = misJugadores[0];
        
        double mejorY = 120.0;
        double mejorNota = 0.0;
        
        for(int i = 0; i < 50; i++)
        {
            double nota = 0.0;
            
            double randomY = Math.random() * 240;
            
            if(randomY > 120)
            {
                randomY -= 120;
                randomY *= -1;
            }
            
            double m = (randomY - portero.y) / (0 - portero.x);
            double b = portero.y - m * portero.x;
            
            for (int x = portero.x; x <= 0.0; x = x + 10)
            {
                double y = m * x + b;
                
                int contrario = sj.getContrarioMasCerca(x, y);
                
                nota += distancia(x, y, contarios[contrario].x, contarios[contrario].y);
            }

            if(nota >= mejorNota)
            {
                mejorNota = nota;
                mejorY = randomY;
            }
        }
        
        comandosJugadores.add(new ComandoGolpearBola(0, 0, mejorY));
    }
    
    private boolean EstaCercaContario(SituacionJugadores sj, int jugEnemigo, int x, int y)
    {
        Point[] contrarios = sj.getContrario();
        
        Point posEnemigo = contrarios[jugEnemigo];
        
        return (20.0 >= distancia(posEnemigo.x, posEnemigo.y, x, y));
    }
    
    /**Retorna la distancia entre dos coodenadas*/
    private double distancia(double x1,double y1,double x0,double y0){
        double dx=(x1-x0);
        double dy=(y1-y0);
        return distancia(dx,dy);
    }
    
    /**Retorna la distancia de una coordenada*/
    private double distancia(double dx,double dy){
        return Math.sqrt(dx*dx+dy*dy);
    }
    
    private void tirar(SituacionJugadores sj, Vector<Comando> comandosJugadores)
    {
        
        for (int i = 10; i > 6; i--)
        {
            if(i > 7)
            {
                comandosJugadores.add(new ComandoTiroAPuerta(i, 0));
            }
            else
            {
                Point result = MejorPunto(i, sj);
                //result = mejorarPunto(i, result);
                
//                double dist=distancia(result.getX(), result.getY(),bola.getX(), bola.getY());
//                int fuerza;
//                if (dist>90)
//                    fuerza=7;
//                else if (dist>40)
//                    fuerza=6;
//                else fuerza=4;
                
                //result = BuscarTiro(i, result.x, result.y, fuerza);
                comandosJugadores.add(new ComandoGolpearBola(i, result.getX(), result.getY()));
            }
        }
    }

    private Point MejorPunto(int i, SituacionJugadores sj) 
    {
        int mejorPunt = Integer.MIN_VALUE;
        Point[] misJugadores = sj.getMisJugadores();
        int xMej = misJugadores[i + 1].x, yMej = misJugadores[i+1].y;
        int punt;

        for (int n = i + 1; n < 11; n++)
        {
            if (n != i)
            {
                punt = heuristica(i, n, sj);
                if (mejorPunt < punt){
                    mejorPunt = punt;
                    xMej=misJugadores[n].x;
                    yMej=misJugadores[n].y;
                }
            }
        }
        return new Point(xMej, yMej);
    }

    private int heuristica(int i, int n, SituacionJugadores sj) 
    {
        Point[] misJugadores = sj.getMisJugadores();
        int fuerza = _jugadores[i][2];
        int vel = fuerza*3;
        int velfinal = calcularVelocidadApunto(misJugadores[i], misJugadores[n], vel);
        if (velfinal > 25)
        {
            return Integer.MIN_VALUE;
        }
        
        //TODO: MEJORAR HEURISTICA
        Point p = misJugadores[n];
        int punt = 0;
        double x = p.x;
        double y = p.y;
        
        Point contrarioCercano = getJugadorMasCercano(p, sj.getContrario());
        if (distancia(p, contrarioCercano) > 10)
        {
            punt += 1000;
        }
        else
        {
            punt -= 1000;
        }
        if(distancia(p, misJugadores[i]) > 150)
        {
            punt -= 1000;
        }
        else
        {
            punt += 1000;
        }
        if(x > misJugadores[i].x)
        {
            punt += 1000;
        }
        //voy para atras
        else
        {
            punt -= 1000;
        }
//        return punt;
        return punt + (new Random()).nextInt(100);
    }
    
     private Point getJugadorMasCercano(Point p, Point[] jugadores) {
        Point cercano = new Point(0, 0);
        int distancia = Integer.MAX_VALUE;
        for(int i = 0; i < 11; i++)
        {
            int temp = distancia(p, jugadores[i]);
            if(distancia > temp)
            {
                distancia = temp;
                cercano = jugadores[i];
            }
        }
        return cercano;
    }
     
      private int distancia(Point p1, Point p2) {
        return (int)Math.sqrt(Math.pow(p1.x-p2.x,2)+Math.pow(p1.y-p2.y,2));
    }
      
      private int calcularVelocidadApunto(Point inicio, Point destino, int velocidad) {
        if (velocidad < 4)
        {
            return 0;
        }
        int dist = distancia(inicio, destino);
        
        while (dist >= 0)
        {
            dist -= velocidad;
            velocidad--;
        }
        return Math.max(velocidad, 0);
    }
}
